AddCSLuaFile( "inventory_shared.lua" )
AddCSLuaFile( "entities/xqam_accessory/shared.lua" )
AddCSLuaFile( "InvBag.lua" )
AddCSLuaFile( "InvStore.lua" )
AddCSLuaFile( "HelpMenu.lua" )

include( "shared.lua" )
include( "inventory_shared.lua" )
include( "server.lua" )

require( "datastream" )
require( "mysql" )


StoreDB = 0
StoreERR = ""

InventoryTable = {}
AbilityTable = {}
AccTable = {}
ACCEntTable = {}


/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MySQL Functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

function InvDBINFO( ply ) //Let's use this for all future MySQL queries
	return mysql.query( DB, "SELECT * FROM inventory WHERE UID = '" .. ply:UniqueID() .. "'" )
end

function InvDBINSERT( ply, data )
	local TS = table.concat( data, "', '" )
	mysql.query( DB, "INSERT INTO inventory (UID, NAME, ROW1, ROW2, ROW3, ROW4, ROW5, ROW6, ROW7, ROW8, ROW9, ROW10, ABILITIESON, ABILITIESOFF, ACCESSORIES) VALUES ('" .. TS .. "')" )
end

function InvDBUPDATE( ply, data )
	local TS = table.concat( data, ", " )
	mysql.query( DB, "UPDATE inventory SET " .. TS .. " WHERE UID ='" .. ply:UniqueID() .. "'" )
end

function StoreDBINFO( DBTable ) //Let's use this for all future MySQL queries
	return mysql.query( StoreDB, "SELECT * FROM " .. DBTable )
end

/*function StoreACCDBINSERT( data )
	local TS = table.concat( data, "', '" )
	mysql.query( StoreDB, "INSERT INTO StoreAccessories (NAME, MODEL, SCALE, OFFSET, ROTATION, INFO, COST) VALUES ('" .. TS .. "')" )
end

function StoreDBINSERT( data, DBTable )
	local TS = table.concat( data, "', '" )
	mysql.query( StoreDB, "INSERT INTO " .. DBTable .. " (NAME, INFO, COST) VALUES ('" .. TS .. "')" )
end*/

function StoreDBUPDATE( data, DBTable )
	local TS = table.concat( data, ", " )
	mysql.query( StoreDB, "UPDATE " .. DBTable .. " SET " .. TS .. " WHERE UID ='" .. ply:UniqueID() .. "'" )
end

function DBInit()
	StoreDB, StoreERR = mysql.connect("127.0.0.1", "POAdmin", "119SHZH", "StoreDB", 3307)
	if StoreDB == 0 then print(StoreERR .. "\n") end
	if StoreDB != 0 then
		print("MySQL Store Database Connection Successful!")
		RebuildStoreTables()
	end
end
hook.Add( "Initialize", "DBInit", DBInit )

function InvSpawn( ply )
	local INVCHECK = InvDBINFO( ply )
	
	if INVCHECK[1] and INVCHECK[1][2] then
		InventoryTable[ply:UniqueID()] = table.concat( INVCHECK[1], ":", 4, 13 )
		AbilityTable[ply:UniqueID()] = table.concat( INVCHECK[1], ":", 14, 15 )
		AccTable[ply:UniqueID()] = INVCHECK[1][16]
		ACCEntTable[ply:UniqueID()] = "EMPTY"
		
		
		if string.find( INVCHECK[1][16], "EMPTY" ) then return end
		if !string.find( INVCHECK[1][16], "," ) then
			EquipACC( ply, INVCHECK[1][16] )
		else
			for k,v in pairs( string.Explode( ",", INVCHECK[1][16] ) ) do
				EquipACC( ply, v )
			end
		end
	else
		local DATA = { ply:UniqueID(), ply:Nick(), "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY", "EMPTY" }
		InvDBINSERT( ply, DATA )
		InventoryTable[ply:UniqueID()] = table.concat( DATA, ":", 3, 12 )
		AbilityTable[ply:UniqueID()] = table.concat( DATA, ":", 13, 14 )
		AccTable[ply:UniqueID()] = DATA[15]
	end
	
end
hook.Add("PlayerInitialSpawn", "InvSpawn", InvSpawn)

function NormalSpawn( ply )	//Add the accessories system here
	local INVCHECK = InvDBINFO( ply )

	for k,v in pairs( string.Explode( ",", INVCHECK[1][14] ) ) do
		if v != "EMPTY" then
			RunConsoleCommand( "Abilities_" .. v, "On", ply:UniqueID() )
		end
	end

end
hook.Add( "PlayerSpawn", "NormalSpawn", NormalSpawn )



/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Shop functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

function RequestPurchase( ply, command, args )
	local PlyPoints = ply:GetNetworkedInt( "points" )
	local Item = args[1]
	local Cost = tonumber(args[2])
	
	if PlyPoints >= Cost then
		if !string.find( InventoryTable[ply:UniqueID()], Item ) then
			AddToInventory( ply, Item, Cost )
			ply:SetNetworkedInt( "points", ply:GetNetworkedInt( "points" ) - Cost )
			DBUPDATE( ply, { "POINTS= " .. ply:GetNetworkedInt( "points" ) } )
		end
	else
		ply:ConCommand( "ErrPlayerNotification" )
	end
	
end
concommand.Add( "RequestPurchase", RequestPurchase )

function AddToInventory( ply, ITEM, COST )
	local INVENTORY = string.Explode( ":", InventoryTable[ply:UniqueID()] )
	local ABILITIES = string.Explode( ":", AbilityTable[ply:UniqueID()] )
	
	for k,v in pairs( INVENTORY ) do
		local ROW = string.Explode( ",", v )
			if table.getn( ROW ) < 45 then
				if INVENTORY[k] ==  "EMPTY" then
					INVENTORY[k] = ITEM
					InventoryTable[ply:UniqueID()] = table.concat( INVENTORY, ":" )
					if string.find( table.concat(StoreAbilities, ","), ITEM ) then
						ABILITIES[2] = ITEM
						AbilityTable[ply:UniqueID()] = table.concat( ABILITIES, ":" )
					end
					InvDBUPDATE( ply, { "NAME= '" .. ply:Nick() .. "'", "ROW1= '" .. INVENTORY[1] .. "'", "ROW2= '" .. INVENTORY[2] .. "'", "ROW3= '" .. INVENTORY[3] .. "'", "ROW4= '" .. INVENTORY[4] .. "'", "ROW5= '" .. INVENTORY[5] .. "'", "ROW6= '" .. INVENTORY[6] .. "'", "ROW7= '" .. INVENTORY[7] .. "'", "ROW8= '" .. INVENTORY[8] .. "'", "ROW9= '" .. INVENTORY[9] .. "'", "ROW10= '" .. INVENTORY[10] .. "'", "ABILITIESOFF= '" .. ABILITIES[2] .. "'" } )
					break
				else
					table.insert( ROW, ITEM )
					INVENTORY[k] = table.concat( ROW, "," )
					InventoryTable[ply:UniqueID()] = table.concat( INVENTORY, ":" )
					
					if string.find( table.concat(StoreAbilities, ","), ITEM ) then
						ABILITIES[2] =  ABILITIES[2] .. "," .. ITEM
						AbilityTable[ply:UniqueID()] = table.concat( ABILITIES, ":" )
					end
					InvDBUPDATE( ply, { "NAME= '" .. ply:Nick() .. "'", "ROW" .. k .. "= '" .. INVENTORY[k] .. "'" } )
					//InvDBUPDATE( ply, { "NAME= '" .. ply:Nick() .. "'", "ROW1= '" .. INVENTORY[1] .. "'", "ROW2= '" .. INVENTORY[2] .. "'", "ROW3= '" .. INVENTORY[3] .. "'", "ROW4= '" .. INVENTORY[4] .. "'", "ROW5= '" .. INVENTORY[5] .. "'", "ROW6= '" .. INVENTORY[6] .. "'", "ROW7= '" .. INVENTORY[7] .. "'", "ROW8= '" .. INVENTORY[8] .. "'", "ROW9= '" .. INVENTORY[9] .. "'", "ROW10= '" .. INVENTORY[10] .. "'", "ABILITIESOFF= '" .. ABILITIES[2] .. "'" } )
					InvDBUPDATE( ply, { "NAME= '" .. ply:Nick() .. "'",  "ABILITIESOFF= '" .. ABILITIES[2] .. "'" } )
					break
				end
			end
	end
	
	//No Clip Flag
	if string.find( table.concat( StoreFLAGS, "," ), ITEM ) then
		if !string.find( ply:GetNetworkedString( "flags" ), "N" ) then
			ply:SetNetworkedString( "flags", DBINFO( ply )[1][7] .. "," .. "N" )
			DBUPDATE( ply, { "FLAGS= '" .. ply:GetNetworkedString( "flags" ) .. "'" } )
		end
		ply:PrintMessage(HUD_PRINTTALK, "You received the N Flag" )
	end
	
	ply:ConCommand( "SuccPlayerNotification" )
	//ply:ConCommand( "RefreshTheStore" )
	StreamInventoryContents( ply )
end

function StreamInventoryContents( ply, command, args )
	local DATA = string.Explode( ":", InventoryTable[ply:UniqueID()] )
	local DATA2 = string.Explode( ":", AbilityTable[ply:UniqueID()] )
	datastream.StreamToClients( { ply }, "InvStream", { ["INVTABLE"] = DATA, ["ABTABLE"] = DATA2, ["AccStr"] = AccTable[ply:UniqueID()] } )
end
concommand.Add( "StreamInvContents", StreamInventoryContents, "StreamInventoryContents" )


/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Item Functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

function AllowTools( pl, tr, toolmode )
	local plyItems = InventoryTable[pl:UniqueID()]
	
	for k,v in pairs( StoreTools ) do
		if string.lower(v) == toolmode then
			if string.find( plyItems, v ) then
				return true
			else
				pl:PrintMessage(HUD_PRINTTALK, "You must purchase this tool before it can be used.")
				return false
			end
		end		
	end

end
hook.Add( "CanTool", "AllowTools", AllowTools )

function AllowSENTs( ply, sent_type )
	local plyItems = InventoryTable[ply:UniqueID()]

	for k,v in pairs( StoreSENTNAMES ) do
		if sent_type == v then
			if string.find( plyItems, StoreSENTs[k] ) then
				return true
			else
				ply:PrintMessage(HUD_PRINTTALK, "You must purchase this SENT before it can be spawned.")
				return false
			end
		end
	end
	
	ply:PrintMessage(HUD_PRINTTALK, "This SENT is unavailable for both spawning and purchasing.")
	return false
end
hook.Add( "PlayerSpawnSENT", "AllowSENTs", AllowSENTs )

function DefaultLoadout( ply )
	ply:Give( "weapon_physcannon" )
	ply:Give( "weapon_physgun" )
	ply:Give( "gmod_tool" )
	ply:Give( "gmod_camera" )
end
hook.Add( "PlayerLoadout", "DefaultLoadout", DefaultLoadout )

function BlockWepPickups( ply, wep )	//Change this later ta allow for store purchases and Owners
	for k,v in pairs( AllowedSWEPS ) do
		if wep:GetClass() == v then return true end
	end
	wep:Remove() return false
end
hook.Add( "PlayerCanPickupWeapon", "BlockWepPickups", BlockWepPickups ) 

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Abilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

function ReplaceABString( ply, Ability, STATUS )
	local ABILITIES = string.Explode( ":", AbilityTable[ply:UniqueID()] )

	if STATUS == "On" then
		if string.find( ABILITIES[2], "," .. Ability ) then
			ABILITIES[2] = string.Replace( ABILITIES[2], "," .. Ability, "" )
		elseif string.find( ABILITIES[2], Ability .. "," ) then
			ABILITIES[2] = string.Replace( ABILITIES[2], Ability .. ",", "" )
		elseif string.find( ABILITIES[2], Ability ) then
			ABILITIES[2] = string.Replace( ABILITIES[2], Ability, "EMPTY" )
		end
		
		if string.find( ABILITIES[1], "EMPTY" ) then
			ABILITIES[1] = Ability
		elseif string.find( ABILITIES[1], Ability ) then
			return
		else
			ABILITIES[1] = ABILITIES[1] .. "," .. Ability
		end
		
		AbilityTable[ply:UniqueID()] = table.concat( ABILITIES, ":" )
		InvDBUPDATE( ply, { "ABILITIESON= '" .. ABILITIES[1] .. "'", "ABILITIESOFF= '" .. ABILITIES[2] .. "'" } )
		StreamInventoryContents( ply )
	elseif STATUS == "Off" then
		if string.find( ABILITIES[1], "," .. Ability ) then
			ABILITIES[1] = string.Replace( ABILITIES[1], "," .. Ability, "" )
		elseif string.find( ABILITIES[1], Ability .. "," ) then
			ABILITIES[1] = string.Replace( ABILITIES[1], Ability .. ",", "" )
		elseif string.find( ABILITIES[1], Ability ) then
			ABILITIES[1] = string.Replace( ABILITIES[1], Ability, "EMPTY" )
		end
		
		if string.find( ABILITIES[2], "EMPTY" ) then
			ABILITIES[2] = Ability
		elseif string.find( ABILITIES[2], Ability ) then
			return
		else
			ABILITIES[2] = ABILITIES[2] .. "," .. Ability
		end
		
		AbilityTable[ply:UniqueID()] = table.concat( ABILITIES, ":" )
		InvDBUPDATE( ply, { "ABILITIESON= '" .. ABILITIES[1] .. "'", "ABILITIESOFF= '" .. ABILITIES[2] .. "'" } )
		StreamInventoryContents( ply )
	end
end


function Extra_Jump_Power( ply, command, args )
	local pl = nil
	if args[2] then
		pl = player.GetByUniqueID( args[2] )
	else
		pl = ply
	end

	if args[1] == "On" then
		pl:SetJumpPower( 500 )
		ReplaceABString( pl, "Extra_Jump_Power", args[1] )
		pl:PrintMessage(HUD_PRINTTALK, "Extra Jump Power On.")
	elseif args[1] == "Off" then
		pl:SetJumpPower( 160 )
		ReplaceABString( pl, "Extra_Jump_Power", args[1] )
		pl:PrintMessage(HUD_PRINTTALK, "Extra Jump Power Off.")
	end
end
concommand.Add( "Abilities_Extra_Jump_Power", Extra_Jump_Power )

function Increased_Run_Speed( ply, command, args )
	local pl = nil
	if args[2] then
		pl = player.GetByUniqueID( args[2] )
	else
		pl = ply
	end

	if args[1] == "On" then
		pl:SetRunSpeed( 2000 )
		ReplaceABString( pl, "Increased_Run_Speed", args[1] )
		pl:PrintMessage(HUD_PRINTTALK, "Increased Run Speed On.")
	elseif args[1] == "Off" then
		pl:SetRunSpeed( 500 )
		ReplaceABString( pl, "Increased_Run_Speed", args[1] )
		pl:PrintMessage(HUD_PRINTTALK, "Increased Run Speed Off.")
	end
end
concommand.Add( "Abilities_Increased_Run_Speed", Increased_Run_Speed )

function Godmode_Ability( ply, command, args )
	local pl = nil
	if args[2] then
		pl = player.GetByUniqueID( args[2] )
	else
		pl = ply
	end
	
	if args[1] == "On" then
		ReplaceABString( pl, "Godmode_Ability", args[1] )
		pl:GodEnable()
		pl:PrintMessage(HUD_PRINTTALK, "Godmode On.")
	elseif args[1] == "Off" then
		ReplaceABString( pl, "Godmode_Ability", args[1] )
		pl:GodDisable()
		pl:PrintMessage(HUD_PRINTTALK, "Godmode Off.")
	end
end
concommand.Add( "Abilities_Godmode_Ability", Godmode_Ability )

function Long_Jump( ply, command, args )
	local pl = nil
	if args[2] then
		pl = player.GetByUniqueID( args[2] )
	else
		pl = ply
	end

	if args[1] == "On" then
		ReplaceABString( pl, "Long_Jump", args[1] )
		pl:PrintMessage(HUD_PRINTTALK, "Long Jump On.")
	elseif args[1] == "Off" then
		ReplaceABString( pl, "Long_Jump", args[1] )
		pl:PrintMessage(HUD_PRINTTALK, "Long Jump Off.")
	end
end
concommand.Add( "Abilities_Long_Jump", Long_Jump )

function PlayerSHIFTJUMP( ply, key )

	if ply:KeyDown( 131072 ) then
		if key == 2 then
			local ABILITIES = string.Explode( ":", AbilityTable[ply:UniqueID()] )
			if string.find(ABILITIES[1], "Long_Jump") and ply:IsOnGround() then
				ply:SetLocalVelocity( ply:GetVelocity() + (ply:GetEyeTraceNoCursor().Normal * 800) )
			end
		end
	end

end
hook.Add( "KeyPress", "PlayerSHIFTJUMP", PlayerSHIFTJUMP )

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Accessories
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

function ToggleACC( ply, command, args )
	local status = args[1]
	local item = args[2]
	local itype = args[3]
	local CheckTable = string.Explode( ",", AccTable[ply:UniqueID()] )
	local MatchedType = ""
	for k,v in pairs( CheckTable ) do
		if string.find( v, itype ) then MatchedType = v break end
	end
	
	if status == "On" then
		if string.find( AccTable[ply:UniqueID()], itype ) then
			print( MatchedType )
			print( ACCEntTable[ply:UniqueID()] )
			RemoveACC( ply, MatchedType )
			
			if string.find( AccTable[ply:UniqueID()], "," .. MatchedType ) then
				AccTable[ply:UniqueID()] = string.Replace( AccTable[ply:UniqueID()], "," .. MatchedType, "" )
			elseif string.find( AccTable[ply:UniqueID()], MatchedType .. "," ) then
				AccTable[ply:UniqueID()] = string.Replace( AccTable[ply:UniqueID()], MatchedType .. ",", "" )
			elseif string.find( AccTable[ply:UniqueID()], MatchedType ) then
				AccTable[ply:UniqueID()] = string.Replace( AccTable[ply:UniqueID()], MatchedType, "EMPTY" )
			end
			
			print( ACCEntTable[ply:UniqueID()] )
			
			InvDBUPDATE( ply, { "ACCESSORIES= '" .. AccTable[ply:UniqueID()] .. "'" } )
			StreamInventoryContents( ply )
		end
	
	
		if string.find( AccTable[ply:UniqueID()], "EMPTY" ) then
			AccTable[ply:UniqueID()] = item
		elseif !string.find( AccTable[ply:UniqueID()], item ) then
			AccTable[ply:UniqueID()] = AccTable[ply:UniqueID()] .. "," .. item
		end
		
		EquipACC( ply, item )
	
		InvDBUPDATE( ply, { "ACCESSORIES= '" .. AccTable[ply:UniqueID()] .. "'" } )
		StreamInventoryContents( ply )
	elseif status == "Off" then
		if string.find( AccTable[ply:UniqueID()], "," .. item ) then
			AccTable[ply:UniqueID()] = string.Replace( AccTable[ply:UniqueID()], "," .. item, "" )
		elseif string.find( AccTable[ply:UniqueID()], item .. "," ) then
			AccTable[ply:UniqueID()] = string.Replace( AccTable[ply:UniqueID()], item .. ",", "" )
		elseif string.find( AccTable[ply:UniqueID()], item ) then
			AccTable[ply:UniqueID()] = string.Replace( AccTable[ply:UniqueID()], item, "EMPTY" )
		end
		
		RemoveACC( ply, item )
		
		InvDBUPDATE( ply, { "ACCESSORIES= '" .. AccTable[ply:UniqueID()] .. "'" } )
		StreamInventoryContents( ply )
	end

end
concommand.Add( "ToggleACC", ToggleACC )

function EquipACC( ply, item )
	print( ACCEntTable[ply:UniqueID()] )
	if !string.find( ACCEntTable[ply:UniqueID()], item ) then
		local itype = ""
		for k,v in pairs( AccessTypes ) do
			if string.find( item, v ) then itype = v end
		end
	
		local ACC = ents.Create( "xqam_accessory" )
			ACC:SetOwner( ply )
			ACC:SetModel( StoreAccModels[item] )
			ACC:SetNetworkedVector( "offset", AccessOffsets[item] )
			ACC:SetNetworkedVector( "scale", AccessSizes[item] )
			ACC:SetNetworkedAngle( "rotation", AccessRotation[item] )
			ACC:SetNetworkedString( "type", itype )
			ACC:Spawn()
			ACC:Activate()	//This is where the Initialize from the server file of the ENT comes in
			
		
		if ACCEntTable[ply:UniqueID()] == "EMPTY" then
			ACCEntTable[ply:UniqueID()] = item .. ":" .. ACC:EntIndex()
			PrintTable( ACCEntTable )
		else
			ACCEntTable[ply:UniqueID()] = ACCEntTable[ply:UniqueID()] .. "," .. item .. ":" .. ACC:EntIndex()
			PrintTable( ACCEntTable )
		end
	end
end

function RemoveACC( ply, item )
	local ACC = nil
	local ACCIndexN = 0
	local TabEnt = ACCEntTable[ply:UniqueID()]
	local TableEnt = string.Explode( ",", ACCEntTable[ply:UniqueID()] )
	local EntID = -1
	
	for k,v in pairs( TableEnt ) do
		if string.find( v, item ) then EntID = tonumber(string.Replace( v, item .. ":", "" ) ) end
	end
	
		if string.find( TabEnt, item ) then
			ACC = ents.GetByIndex( EntID )
			
			if string.find( TabEnt, item .. ":" .. EntID .. "," ) then
				ACCEntTable[ply:UniqueID()] = string.Replace( TabEnt, item .. ":" .. EntID .. ",", "" )
			elseif string.find( TabEnt, "," .. item .. ":" .. EntID ) then
				ACCEntTable[ply:UniqueID()] = string.Replace( TabEnt, "," .. item .. ":" .. EntID, "" )
			elseif string.find( TabEnt, item .. ":" .. EntID ) then
				ACCEntTable[ply:UniqueID()] = string.Replace( TabEnt, item .. ":" .. EntID, "EMPTY" )
			end
			
			ACC:Remove()
		end
end